////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __WN_CONTAINERS_CALLBACK_H__
#define __WN_CONTAINERS_CALLBACK_H__

#include "WNCore/inc/WNTypes.h"
#include "WNMemory/inc/WNAllocation.h"

namespace WNContainers {
    namespace __WNInternal {
        template <typename Return>
        class __WNCallbackBase0 {
        public:
            __WNCallbackBase0();
            virtual ~__WNCallbackBase0() {}
            virtual Return Execute() const = 0;

            WN_VOID AddRef();
            WN_ATOM_T RemoveRef();

        private:
            WN_ATOM_T mCount;
        };

        template <typename Return, typename Parameter>
        class __WNCallbackBase1 {
        public:
            __WNCallbackBase1();
            virtual ~__WNCallbackBase1() {}
            virtual Return Execute(const Parameter& _parameter) const = 0;

            WN_VOID AddRef();
            WN_ATOM_T RemoveRef();

        private:
            WN_ATOM_T mCount;
        };

        template<typename Return, typename Parameter1, typename Parameter2>
        class __WNCallbackBase2 {
        public:
            __WNCallbackBase2();
            virtual ~__WNCallbackBase2() {}
            virtual Return Execute(const Parameter1& _parameter1, const Parameter2& _parameter2) const = 0;

            WN_VOID AddRef();
            WN_ATOM_T RemoveRef();

        private:
            WN_ATOM_T mCount;
        };

        template<typename Return, typename Parameter1, typename Parameter2, typename Parameter3>
        class __WNCallbackBase3 {
        public:
            __WNCallbackBase3();
            virtual ~__WNCallbackBase3() {}
            virtual Return Execute(const Parameter1& _parameter1, const Parameter2& _parameter2, const Parameter3& _parameter3) const = 0;

            WN_VOID AddRef();
            WN_ATOM_T RemoveRef();

        private:
            WN_ATOM_T mCount;
        };
    }

    template <typename Return>
    class WNCallback0 {
    public:
        WNCallback0();
        WNCallback0(const WNCallback0<Return>& _callback);
        WNCallback0(Return (*_function)());

        template <typename Type>
        WNCallback0(Type* _this, Return (Type::*_function)());

        virtual ~WNCallback0();

        WNCallback0<Return>& operator = (const WNCallback0<Return>& _callback);

        Return Execute() const;

    private:
        __WNInternal::__WNCallbackBase0<Return>* mBaseCallback;
    };

    template <typename Return, typename Parameter>
    class WNCallback1 {
    public:
        WNCallback1();
        WNCallback1(const WNCallback1<Return, Parameter>& _callback);
        WNCallback1(Return (*_function)(Parameter));

        template <typename Type>
        WNCallback1(Type* _this, Return (Type::*_function)(Parameter));

        virtual ~WNCallback1();

        WNCallback1<Return, Parameter>& operator = (const WNCallback1<Return, Parameter>& _callback);

        Return Execute(const Parameter& _parameter) const;

    private:
        __WNInternal::__WNCallbackBase1<Return, Parameter>* mBaseCallback;
    };

    template <typename Return, typename Parameter1, typename Parameter2>
    class WNCallback2 {
    public:
        WNCallback2();
        WNCallback2(const WNCallback2<Return, Parameter1, Parameter2>& _callback);
        WNCallback2(Return (*_function)(Parameter1, Parameter2));

        template<typename Type>
        WNCallback2(Type* _this, Return (Type::*_function)(Parameter1, Parameter2));

        virtual ~WNCallback2();

        WNCallback2<Return, Parameter1, Parameter2>& operator = (const WNCallback2<Return, Parameter1, Parameter2>& _callback);

        Return Execute(const Parameter1& _parameter1, const Parameter2& _parameter2) const;

    private:
        __WNInternal::__WNCallbackBase2<Return, Parameter1, Parameter2>* mBaseCallback;
    };

    template <typename Return, typename Parameter1, typename Parameter2, typename Parameter3>
    class WNCallback3 {
    public:
        WNCallback3();
        WNCallback3(const WNCallback3<Return, Parameter1, Parameter2, Parameter3>& _callback);
        WNCallback3(Return (*_function)(Parameter1, Parameter2, Parameter3));

        template<typename Type>
        WNCallback3(Type* _this, Return (Type::*_function)(Parameter1, Parameter2, Parameter3));

        virtual ~WNCallback3();

        WNCallback3<Return, Parameter1, Parameter2, Parameter3>& operator = (const WNCallback3<Return, Parameter1, Parameter2, Parameter3>& _callback);

        Return Execute(const Parameter1& _parameter1, const Parameter2& _parameter2, const Parameter3& _parameter3) const;

    private:
        __WNInternal::__WNCallbackBase3<Return, Parameter1, Parameter2, Parameter3>* mBaseCallback;
    };
}

#include "WNContainers/inc/WNCallback.inl"

#endif // __WN_CONTAINERS_CALLBACK_H__
